package com.garmin.gh.apps.wellnessmonitor.controller;

import java.io.IOException;
import java.util.List;

import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.garmin.gh.apps.wellnessmonitor.dao.h2.UserPartnerDao;
import com.garmin.gh.apps.wellnessmonitor.dao.h2.WellnessDao;
import com.garmin.gh.apps.wellnessmonitor.domain.SummaryData;
import com.garmin.gh.apps.wellnessmonitor.domain.UserPartner;
import com.garmin.gh.apps.wellnessmonitor.domain.ping.Deregistrations;
import com.garmin.gh.apps.wellnessmonitor.domain.ping.PingBody;
import com.garmin.gh.apps.wellnessmonitor.domain.ping.PingNotificationForDereg;
import com.garmin.gh.apps.wellnessmonitor.service.UploadService;
import com.garmin.gh.apps.wellnessmonitor.util.Consts;


/**
 * This controller exercises the core ping/pull implementation.
 * It accepts change notifications from the Garmin Health servers and fetches data
 * based on the provided callback URL. You may choose to have an endpoint for each data type
 * or a single endpoint to handle them all - the target for these notifications is
 * configurable at /wellness-api/web/ping on a per-type basis. 
 *
 */

@RestController
@EnableAutoConfiguration
@Component
@RequestMapping("/ping")
public class WellnessPingController
{

    private static final Logger logger = LoggerFactory.getLogger(WellnessPingController.class);
    private static final String PING = "ping";
    private static final String WARNING_MESSAGE = "Summarydata is not available";


    ObjectMapper jackson = new ObjectMapper();
    
    @Autowired
    UploadService uploadService;
    
    @Autowired
    UserPartnerDao userPartnerDao;
    
    @Autowired
    WellnessDao wellnessDao;


    //Your Health API Consumer Key
    @Value("${oauth.consumerkey}")
    private String consumerkey;

    @Value("${oauth.consumerSecret}")
    private String consumerSecret;

    /**
     * Accept Daily Summary pings, perform the callback to the Health API, and persist the resulting data.
     */
   
    @RequestMapping(value = "/dailies", method = RequestMethod.POST)
    public ResponseEntity<String> handleDailiesPingNotification(@RequestBody @Valid PingBody dailies)

    {
        if (dailies != null && dailies.getDailies() != null && dailies.getDailies().size() > 0)
        {
            return  uploadService.invokeHealthApi( dailies.getDailies(),Consts.DAILIES);
        }
        else
        {
            logger.info("sending acknowledgement - 204 for dailies ping notification service");
            return new ResponseEntity<String>(HttpStatus.NO_CONTENT);
        }
    }

    @RequestMapping(value = "/thirdPartyDailies", method = RequestMethod.POST)
    public ResponseEntity<String> handleThirdPartyDailiesPingNotification(
        @RequestBody @Valid PingBody thirdPartyDailies)

    {
        if (thirdPartyDailies != null && thirdPartyDailies.getThirdPartyDailies() != null
            && thirdPartyDailies.getThirdPartyDailies().size() > 0)
        {
            return  uploadService.invokeHealthApi(thirdPartyDailies.getThirdPartyDailies(),Consts.THIRD_PARTY_DAILIES);
        }
        else
        {
            logger.info("sending acknowledgement - 204 for thirdpartydailies ping notification service");
            return new ResponseEntity<String>(HttpStatus.NO_CONTENT);
        }
    }

    @RequestMapping(value = "/activities", method = RequestMethod.POST)
    public ResponseEntity<String> handleActivityPingNotification(@RequestBody @Valid PingBody activities)
    {

        if (activities != null && activities.getActivities() != null && activities.getActivities().size() > 0)
        {
            return  uploadService.invokeHealthApi(activities.getActivities(),Consts.ACTIVITIES);
        }
        else
        {
            logger.info("sending acknowledgement - 204  for activities ping notification service");
            return new ResponseEntity<String>(HttpStatus.NO_CONTENT);
        }
    }

    @RequestMapping(value = "/epochs", method = RequestMethod.POST)
    public ResponseEntity<String> handleEpochsPingNotification(@RequestBody @Valid PingBody epochs)
    {

        if (epochs != null && epochs.getEpochs() != null && epochs.getEpochs().size() > 0)
        {
        	return  uploadService.invokeHealthApi(epochs.getEpochs(),Consts.EPOCHS);
        }
        else
        {
            logger.info("sending acknowledgement - 204 for epochs ping notification service");
            return new ResponseEntity<String>(HttpStatus.NO_CONTENT);
        }
    }

    @RequestMapping(value = "/sleeps", method = RequestMethod.POST)
    public ResponseEntity<String> handleSleepsPingNotification(@RequestBody @Valid PingBody sleeps)
    {
        logger.info("Sleeps ping notification");
        if (sleeps != null && sleeps.getSleeps() != null && sleeps.getSleeps().size() > 0)
        {
            return  uploadService.invokeHealthApi(sleeps.getSleeps(),Consts.SLEEPS);
        }
        else
        {
            logger.info("sending acknowledgement - 204 for sleeps ping notification service");
            return new ResponseEntity<String>(HttpStatus.NO_CONTENT);
        }
    }

    @RequestMapping(value = "/bodyComps", method = RequestMethod.POST)
    public ResponseEntity<String> handleBodyCompsPingNotification(@RequestBody @Valid PingBody bodyComps)
    {
        logger.info("BodyComps ping notification");
        if (bodyComps != null && bodyComps.getBodyComps() != null && bodyComps.getBodyComps().size() > 0)
        {
            return  uploadService.invokeHealthApi(bodyComps.getBodyComps(),Consts.BODYCOMPS);
        }
        else
        {
            logger.info("sending acknowledgement - 204 for bodyComps ping notification service");
            return new ResponseEntity<String>(HttpStatus.NO_CONTENT);
        }
    }

    @RequestMapping(value = "/stress", method = RequestMethod.POST)
    public ResponseEntity<String> handleStressPingNotification(@RequestBody @Valid PingBody stressDetails)
    {
        logger.info("Stress ping notification");
        if (stressDetails != null && stressDetails.getStressDetails()!= null && stressDetails.getStressDetails().size() > 0)
        {
            return  uploadService.invokeHealthApi(stressDetails.getStressDetails(),Consts.STRESS);
        }
        else
        {
            logger.info("sending acknowledgement - 204 for stress ping notification service");
            return new ResponseEntity<String>(HttpStatus.NO_CONTENT);
        }
    }
    
    @RequestMapping(value = "/activityUpdates", method = RequestMethod.POST)
    public ResponseEntity<String> handleActivityUpdatePingNotification(
        @RequestBody @Valid PingBody manuallyUpdatedActivities)
    {
        logger.info("ActivityUpdate ping notification");
        if (manuallyUpdatedActivities != null && manuallyUpdatedActivities.getManuallyUpdatedActivities() != null
            && manuallyUpdatedActivities.getManuallyUpdatedActivities().size() > 0)
        {
            return  uploadService.invokeHealthApi(manuallyUpdatedActivities.getManuallyUpdatedActivities(),Consts.ACTIVITYUPDATES);
        }
        else
        {
            logger.info("sending acknowledgement - 204 for activityUpdates ping notification service");
            return new ResponseEntity<String>(HttpStatus.NO_CONTENT);
        }
    }

    @RequestMapping(value = "/deRegistrations", method = RequestMethod.POST)
    public ResponseEntity<String> handleDeregistrationPingNotification(
        @RequestBody @Valid Deregistrations deregistrations)
    {
        logger.info("Deregistration ping notification");
        if (deregistrations != null && deregistrations.getDeregistrations() != null
            && deregistrations.getDeregistrations().size() > 0)
        {
            for(PingNotificationForDereg deregistration:deregistrations.getDeregistrations())
            {
                logger.info("Deregistration ping notification data:userAccessToken:{}", deregistration.getUserAccessToken());
                logger.info("Deleting useraccesstoken information in userpartner table");
                UserPartner userPartnerTable = userPartnerDao.findByToken(deregistration
                    .getUserAccessToken());
                if (userPartnerTable != null)
                {
                    userPartnerDao.delete(userPartnerTable.getUserId());
                }
                // have to go for oauthprocess for this user to get a new useraccesstoken
            }
            return new ResponseEntity<String>(HttpStatus.OK);
        }
        else
        {
            return new ResponseEntity<String>(HttpStatus.NO_CONTENT);
        }
    }

    
    // Endpoints to get the latest  pulled  data.

    @RequestMapping(value = "/activitySummary/{consumerKey}/{useraccessToken}", method = RequestMethod.GET,produces = "application/json")
    private String displayActivitiesPingSummaryData(@PathVariable String consumerKey,
        @PathVariable String useraccessToken) throws JsonParseException, JsonMappingException, JsonProcessingException,
        IOException
    {
        List<SummaryData> activitiesSummaryDataList = wellnessDao.findPingSummaryDataByDomain(Consts.ACTIVITIES, PING,
            consumerKey, useraccessToken);
        String activityInfo;
        if (activitiesSummaryDataList.size() > 0)
        {
            activityInfo = activitiesSummaryDataList.get(0).getDataLob();
        }
        else
        {
            activityInfo = Consts.ACTIVITIES + WARNING_MESSAGE;
        }
        return activityInfo;
    }

    @RequestMapping(value = "/dailiesSummary/{consumerKey}/{useraccessToken}", method = RequestMethod.GET,produces = "application/json")
    private String displayDailiesPingSummaryData(@PathVariable String consumerKey, @PathVariable String useraccessToken)
        throws JsonParseException, JsonMappingException, JsonProcessingException, IOException
    {
        List<SummaryData> dailiesSummaryDataList = wellnessDao.findPingSummaryDataByDomain(Consts.DAILIES, PING,
            consumerKey, useraccessToken);
        String dailiesInfo;
        if (dailiesSummaryDataList.size() > 0)
        {
            dailiesInfo = dailiesSummaryDataList.get(0).getDataLob();
        }
        else
        {
            dailiesInfo = jackson.writeValueAsString(Consts.DAILIES + WARNING_MESSAGE);
        }
        return dailiesInfo;
    }

    @RequestMapping(value = "/epochSummary/{consumerKey}/{useraccessToken}", method = RequestMethod.GET, produces = "application/json")
    private String displayEpochsPingSummaryData(@PathVariable String consumerKey, @PathVariable String useraccessToken) throws IOException
       
    {
        List<SummaryData> epochsSummaryDataList = wellnessDao.findPingSummaryDataByDomain(Consts.EPOCHS, PING,
            consumerKey, useraccessToken);
        String epochInfo;
        if (epochsSummaryDataList.size() > 0)
        {
            epochInfo = epochsSummaryDataList.get(0).getDataLob();
        }
        else
        {
            epochInfo = jackson.writeValueAsString(Consts.EPOCHS + WARNING_MESSAGE);
        }
        return epochInfo;
    }

    @RequestMapping(value = "/sleepSummary/{consumerKey}/{useraccessToken}", method = RequestMethod.GET, produces ="application/json")
    private String displaySleepsPingSummaryData(@PathVariable String consumerKey, @PathVariable String useraccessToken)
        throws JsonParseException, JsonMappingException, JsonProcessingException, IOException
    {
        List<SummaryData> sleepsSummaryDataList = wellnessDao.findPingSummaryDataByDomain(Consts.SLEEPS, PING,
            consumerKey, useraccessToken);
        String sleepInfo;
        if (sleepsSummaryDataList.size() > 0)
        {
            sleepInfo = sleepsSummaryDataList.get(0).getDataLob();
        }
        else
        {
            sleepInfo = jackson.writeValueAsString(Consts.SLEEPS + WARNING_MESSAGE);
        }
        return sleepInfo;
    }

    @RequestMapping(value = "/bodyCompsSummary/{consumerKey}/{useraccessToken}", method = RequestMethod.GET, produces = "application/json")
    private String displayBodyCompsPingSummaryData(@PathVariable String consumerKey,
        @PathVariable String useraccessToken) throws JsonParseException, JsonMappingException, JsonProcessingException,
        IOException
    {
        List<SummaryData> bodyCompsSummaryDataList = wellnessDao.findPingSummaryDataByDomain(Consts.BODYCOMPS, PING,
            consumerKey, useraccessToken);
        String bodyCompInfo;
        if (bodyCompsSummaryDataList.size() > 0)
        {
            bodyCompInfo = bodyCompsSummaryDataList.get(0).getDataLob();
        }
        else
        {
            bodyCompInfo = jackson.writeValueAsString(Consts.BODYCOMPS + WARNING_MESSAGE);
        }
        return bodyCompInfo;
    }

    @RequestMapping(value = "/activityUpdateSummary/{consumerKey}/{useraccessToken}", method = RequestMethod.GET, produces = "application/json")
    private String displayactivityUpdatesPingSummaryData(@PathVariable String consumerKey,
        @PathVariable String useraccessToken) throws JsonParseException, JsonMappingException, JsonProcessingException,
        IOException
    {
        List<SummaryData> activityUpdateSummaryDataList = wellnessDao.findPingSummaryDataByDomain(
            Consts.ACTIVITYUPDATES, PING, consumerKey, useraccessToken);
        String activityUpdateInfo;
        if (activityUpdateSummaryDataList.size() > 0)
        {
            activityUpdateInfo = activityUpdateSummaryDataList.get(0).getDataLob();
        }
        else
        {
            activityUpdateInfo = jackson.writeValueAsString(Consts.ACTIVITYUPDATES + WARNING_MESSAGE);
        }
        return activityUpdateInfo;
    }
    
    @RequestMapping(value = "/stressSummary/{consumerKey}/{useraccessToken}", method = RequestMethod.GET, produces = "application/json")
    private String displayStressPingSummaryData(@PathVariable String consumerKey,
        @PathVariable String useraccessToken) throws JsonParseException, JsonMappingException, JsonProcessingException,
        IOException
    {
        List<SummaryData> stressSummaryDataList = wellnessDao.findPingSummaryDataByDomain(
            Consts.STRESS, PING, consumerKey, useraccessToken);
        String stressInfo;
        if (stressSummaryDataList.size() > 0)
        {
            stressInfo = stressSummaryDataList.get(0).getDataLob();
        }
        else
        {
            stressInfo = jackson.writeValueAsString(Consts.STRESS + WARNING_MESSAGE);
        }
        return stressInfo;
    }
   
}
